<template>
	<view ref="bodywk" @click="hanlder" :class="[customClass, 'overflow']" :style="[
			computedHeight ? { height: computedHeight } : '', 
			computedWidth ? { width: computedWidth } : '',customCSSStyle]">
		<view v-if="isLoadEl" ref="nvueElAni" :animation="animationData" :class="[
			'flex-col flex trani',
			animationName+reverseAniPrefxname,customClass
		]" >
			<slot name="default"></slot>
		</view>
	</view>
</template>

<script lang="ts" setup>
	/**
	 * 动画
	 * @description 提供了6组动画，并且每组件动画都支持反转播放，相当于12组动画了。可用于任何元素，进入场和出场的动画。
	 */
	import {
		getCurrentInstance,
		computed,
		ref,
		provide,
		inject,
		onMounted,
		onUnmounted,
		nextTick,
		watch
	} from 'vue';
	import {
		cssstyle,
		tmVuetify
	} from '../../tool/lib/interface';
	import {
		custom_props,
		computedClass,
		computedStyle
	} from '../../tool/lib/minxs';
	// #ifdef APP-PLUS-NVUE
	const Binding = uni.requireNativePlugin('bindingx');
	const dom = uni.requireNativePlugin('dom')
	// #endif
	// 混淆props共有参数
	const props = defineProps({
		...custom_props,
		duration: {
			type: Number,
			default: 300
		},
		delay: {
			type: Number,
			default: 0
		},
		//动画名称
		name: {
			type: String,
			default: 'fade', //fade,left,right,up,down,zoom
		},
		autoPlay: {
			type: Boolean,
			default: true
		},
		disabled: {
			type: Boolean,
			default: false
		},
		height: {
			type: [Number, String],
			default: 0
		},
		width: {
			type: [Number, String],
			default: 0
		},
		//是否反向动画
		reverse: {
			type: [Boolean, String],
			default: false
		},
		//每变动一次，就重置动画一下，这个属性不对外，特殊情况使用。
		initByWechat:{
			type:Boolean,
			default:false
		}
	});
	const emits = defineEmits(['start', 'end', 'click']);

	function hanlder(e) {
		emits("click", e)
	}
	const proxy = getCurrentInstance()?.proxy??null;
	//自定义样式：
	const customCSSStyle = computed(() => computedStyle(props));
	//自定类
	const customClass = computed(() => computedClass(props));
	//高度，
	const computedHeight = computed(() => {
		if (!props.height || !Number(props.height)) {
			return 0
		}
		if (String(props.height).indexOf('px') > -1 || String(props.height).indexOf('rpx') > -1) {
			return String(props.height);
		}
		return String(props.height) + 'rpx';
	});

	// 宽度
	const computedWidth = computed(() => {
		if (!props.width) {
			return 0;
		}
		if (String(props.width).indexOf('px') > -1 || String(props.width).indexOf('rpx') > -1) {
			return props.width;
		}
		return props.width + 'rpx'
	})
	//动画名称
	const animationName = computed(() => props.name || "fade")
	//动画时长
	const durationtos = computed(() => props.duration)
	//是否反转。
	const computedReverse = computed(() => props.reverse)
	//反转动画前缀
	const reverseAniPrefxname = computed(() => computedReverse.value ? '-reverse' : '')
	//动画播放状态。0未开始,结束播放，1开始播放中,2结束。
	const animationStatus = ref(0)
	const tmid = ref(Number(uni.$tm.u.getUid(3)));
	//是否渲染完成。
	const isLoadEl = ref(false);
	//css3动画数据。
	const animationData = ref(null);
	let testid =99
	watch(()=>props.initByWechat,()=>{
		reset()
	})
	function init() {
		nextTick(()=>{
			isLoadEl.value = true;
			if (props.autoPlay == true && !props.disabled) {
				play()
			}
		})
	}

	function play() {
		if (props.disabled == true) return;
		animationStatus.value = 0;
		// #ifdef APP-NVUE
		clearTimeout(tmid.value)
		nextTick(function() {
			tmid.value = setTimeout(function() {
				nvueAmatons();
			}, 50);
		})
		// #endif
		// #ifndef APP-PLUS-NVUE
		noNvueAmations();
		// #endif
	}

	function stop() {
		if (props.disabled == true) return;
		clearTimeout(tmid.value);
		animationStatus.value = 0;
		// noNvueAmationsReset()
	}

	function reset() {
		stop();
		animationStatus.value = 0;
	}
	//对外暴露方法。
	defineExpose({
		init: init,
		play: play,
		stop: stop,
		reset: reset
	})
	//获取当前播放状态。
	function getPlayStatus() {
		return animationStatus.value;
	}

	function getEl(el) {
		if (typeof el === 'string' || typeof el === 'number') return el;
		if (WXEnvironment) {
			return el.ref;
		} else {
			return el instanceof HTMLElement ? el : el.$el;
		}
	}
	onMounted(() => init())
	onUnmounted(() => {
		clearTimeout(tmid.value);
		animationStatus.value = 0;
	})

	function nvueAmatons() {
		var el = proxy.$refs.nvueElAni;
		let propsAni = {};
		
		dom.getComponentRect(el, function(res) {
			const {
				width,
				height
			} = res.size;
			let elDom = getEl(el);
			if (animationName.value == 'fade') {
				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
						element: elDom,
						property: 'opacity',
						expression: `linear(t,0,1,${durationtos.value})`
					}]
				}
			} else if (animationName.value == 'up') {
				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
						element: elDom,
						property: 'transform.translateY',
						expression: computedReverse.value ?
							`easeOutSine(t,-${height},${height},${durationtos.value})` :
							`linear(t,${0},-${height},${durationtos.value})`
					}]
				}
			} else if (animationName.value == 'down') {
				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
						element: elDom,
						property: 'transform.translateY',
						expression: computedReverse.value ?
							`easeOutSine(t,${height},-${height},${durationtos.value})` :
							`linear(t,${0},${height},${durationtos.value})`
					}]
				}
			} else if (animationName.value == 'right') {
				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
						element: elDom,
						property: 'transform.translateX',
						expression: computedReverse.value ?
							`easeOutSine(t,${width},-${width},${durationtos.value})` :
							`linear(t,${0},${width},${durationtos.value})`
					}]
				}
			} else if (animationName.value == 'left') {
				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
						element: elDom,
						property: 'transform.translateX',
						expression: computedReverse.value ?
							`easeOutSine(t,-${width},${width},${durationtos.value})` :
							`linear(t,${0},-${width},${durationtos.value})`
					}]
				}
			} else if (animationName.value == 'zoom') {

				propsAni = {
					exitExpression: `t>${durationtos.value}`,
					props: [{
							element: elDom,
							property: 'transform.scale',
							expression: computedReverse.value ?
								`linear(t,1,-0.7,${durationtos.value})` :
								`linear(t,0.7,0.3,${durationtos.value})`
						},
						{
							element: elDom,
							property: 'opacity',
							expression: computedReverse.value ?
								`linear(t,1,-1,${durationtos.value})` :
								`linear(t,0,1,${durationtos.value})`
						}
					]
				}
			}

			emits('start');
			animationStatus.value = 1;
			let main_binding = Binding.bind({
				eventType: 'timing',
				...propsAni
			}, function(res) {
				if (res.state === 'exit') {
					emits('end');
					animationStatus.value = 2;
					Binding.unbind({
						token: res.token,
						eventType: 'timing'
					})
				}
			});
		})

	}
	

	function noNvueAmations() {

		animationData.value = null;
		
		//复位。
		nextTick(function() {
			var animation = uni.createAnimation({
				duration: durationtos.value,
				timingFunction: 'ease',
				delay: 30
			});
			
			clearTimeout(tmid.value)
			if (animationName.value == 'fade') {
				let opacity = computedReverse.value ? 1 : 0;
				animation.opacity(opacity).step({
					duration: 0
				});
			} else if (animationName.value == 'up') {
				let opacity = computedReverse.value ? '-101%' : '0%';
				animation.translateY(opacity).step({
					duration: 0
				});
			} else if (animationName.value == 'down') {
				let opacity = computedReverse.value ? '101%' : '0%';
				animation.translateY(opacity).step({
					duration: 0
				});
			} else if (animationName.value == 'left') {
				let opacity = computedReverse.value ? '-101%' : '0%';
				animation.translateX(opacity).step({
					duration: 0
				});
			} else if (animationName.value == 'right') {
				let opacity = computedReverse.value ? '101%' : '0';
				animation.translateX(opacity).step({
					duration: 0
				});
			} else if (animationName.value == 'zoom') {
				let scale = computedReverse.value ? [1, 1] : [0.7, 0.7];
				let opacity = computedReverse.value ? 1 : 0;
				animation.scale(...scale).opacity(opacity).step({
					duration: 0
				});
			}
			animationData.value = animation.export();
			let detalTime = 40;
			// #ifdef MP
			detalTime=80
			// #endif
			tmid.value = setTimeout(function() {
				if (animationName.value == 'fade') {
					let opacity = computedReverse.value ? 0 : 1;
					animation.opacity(opacity).step();
				} else if (animationName.value == 'up') {
					let opacity = computedReverse.value ? '0%' : '-101%';
					animation.translateY(opacity).step();
				} else if (animationName.value == 'down') {
					let opacity = computedReverse.value ? '0%' : '101%';
					animation.translateY(opacity).step();
				} else if (animationName.value == 'left') {
					let opacity = computedReverse.value ? '0%' : '-101%';
					animation.translateX(opacity).step();
				} else if (animationName.value == 'right') {
					let opacity = computedReverse.value ? '0' : '101%';
					animation.translateX(opacity).step();
				} else if (animationName.value == 'zoom') {
					let scale = computedReverse.value ? [0.7, 0.7] : [1, 1];
					let opacity = computedReverse.value ? 0 : 1;
					animation.scale(...scale).opacity(opacity).step();
				}
				emits('start');
				animationData.value = animation.export();
				animationStatus.value = 1;
				clearTimeout(tmid.value)
				tmid.value = setTimeout(function() {
					emits('end');
					animationStatus.value = 2;
				}, durationtos.value)
			}, detalTime)
		})
	}
</script>

<style scoped>

	.fade {
		opacity: 0;
	}
	.fade-reverse {
		opacity: 1;
	}

	.up {
		transform: translate3d(0,0%0);
	}

	.up-reverse {
		transform: translateY(-101%);
	}

	.down {
		transform: translateY(0%);
	}

	.down-reverse {
		transform: translateY(101%);
	}

	.left {
		transform: translateX(0%);
	}

	.left-reverse {
		transform: translateX(-101%);
	}

	.right {
		transform: translateX(0%);
	}

	.right-reverse {
		transform: translateX(101%);
	}

	.zoom {
		transform: scale(0.7, 0.7);
		opacity: 0;
	}

	.zoom-reverse {
		transform: scale(1, 1);
		opacity: 1;
	}

</style>
